#include "util.h"

void vReadFile(const char * pcFileName, char * pcData)
{
    FILE *f = fopen(pcFileName, "rb");
    fseek(f, 0, SEEK_END);
    long len = ftell(f);
    fseek(f, 0, SEEK_SET);
    fread(pcData, 1, len, f);
    fclose(f);
}

void WalkJsonObject(int level, cJSON * json,
    const google::protobuf::Descriptor* pMsgDesc,
    google::protobuf::Message* pMsg)
{
    printf("\n\n%s, level = %d\n", __FUNCDNAME__, level);

    int iSize = cJSON_GetArraySize(json);
    printf("level = %d, iSize = %d\n", level, iSize);
    for (int i = 0; i < iSize; i++)
    {
        cJSON *pItem = cJSON_GetArrayItem(json, i);
        const FieldDescriptor * field = pMsgDesc->FindFieldByName(string(pItem->string));
        const Reflection * reflection = pMsg->GetReflection();
        printf("level = %d, object sub[%d], name = %s, type = %d\n", level, i, pItem->string, pItem->type);

        switch (pItem->type)
        {
        case cJSON_False:
        {
            printf("level = %d, cJSON_False, pItem->valueint = %d\n", level, pItem->valueint);
            reflection->SetBool(pMsg, field, false);
        }
        break;
        case cJSON_True:
        {
            printf("level = %d, cJSON_True, pItem->valueint = %d\n", level, pItem->valueint);
            reflection->SetBool(pMsg, field, true);
        }
        break;
        case cJSON_NULL:
        {
            printf("level = %d, cJSON_NULL\n", level);
        }
        break;
        case cJSON_Number:
        {
            printf("level = %d, cJSON_Number, pItem->valueint = %d\n", level, pItem->valueint);
            reflection->SetInt32(pMsg, field, pItem->valueint);
        }
        break;
        case cJSON_String:
        {
            printf("level = %d, cJSON_String, pItem->valuestring = %s\n", level, pItem->valuestring);
            reflection->SetString(pMsg, field, string(pItem->valuestring));
        }
        break;
        case cJSON_Array:
        {
            printf("level = %d, cJSON_Array\n", level);
            WalkJsonArray(level + 1, pItem, pMsgDesc, pMsg);
        }
        break;
        case cJSON_Object:
        {
            printf("level = %d, cJSON_Object, pItem->string = %s\n", level, pItem->string);
            const Descriptor* pSubDesc = field->message_type();
            Message* pSubMsg = reflection->MutableMessage(pMsg, field);
            WalkJson(level + 1, pItem, pSubDesc, pSubMsg);
        }
        break;
        default:
        {
            printf("level = %d, unknown type = %d\n", level, pItem->type);
        }
        break;
        }
    }
}

void WalkJsonArray(int level, cJSON * json,
    const google::protobuf::Descriptor* pMsgDesc,
    google::protobuf::Message* pMsg)
{
    printf("\n\n%s, level = %d\n", __FUNCDNAME__, level);

    const FieldDescriptor * field = pMsgDesc->FindFieldByName(string(json->string));
    const Reflection * reflection = pMsg->GetReflection();

    int iArrSize = cJSON_GetArraySize(json);
    printf("level = %d, iArrSize = %d\n", level, iArrSize);
    for (int j = 0; j < iArrSize; j++)
    {
        cJSON *pItem = cJSON_GetArrayItem(json, j);
        printf("level = %d, array sub[%d], name = %s, type = %d\n", level, j, pItem->string, pItem->type);

        switch (pItem->type)
        {
        case cJSON_False:
        {
            printf("level = %d, cJSON_False, pItem->valueint = %d\n", level, json->valueint);
            reflection->AddBool(pMsg, field, false);
        }
        break;
        case cJSON_True:
        {
            printf("level = %d, cJSON_True, pItem->valueint = %d\n", level, json->valueint);
            reflection->AddBool(pMsg, field, true);
        }
        break;
        case cJSON_NULL:
        {
            printf("level = %d, cJSON_NULL\n", level);
        }
        break;
        case cJSON_Number:
        {
            printf("level = %d, cJSON_Number, pItem->valueint = %d\n", level, pItem->valueint);
            reflection->AddInt32(pMsg, field, pItem->valueint);
        }
        break;
        case cJSON_String:
        {
            printf("level = %d, cJSON_String, pItem->valuestring = %s\n", level, pItem->valuestring);
            reflection->AddString(pMsg, field, pItem->valuestring);
        }
        break;
        case cJSON_Array:
        {
            printf("level = %d, cJSON_Array\n", level);
            const Descriptor* pSubDesc = field->message_type();
            Message* pSubMsg = reflection->AddMessage(pMsg, field);
            WalkJsonArray(level + 1, pItem, pSubDesc, pSubMsg);
        }
        break;
        case cJSON_Object:
        {
            printf("level = %d, cJSON_Object, pItem->string = %s\n", level, pItem->string);
            const Descriptor* pSubDesc = field->message_type();
            Message* pSubMsg = reflection->AddMessage(pMsg, field);
            WalkJsonObject(level + 1, pItem, pSubDesc, pSubMsg);
        }
        break;
        default:
        {
            printf("level = %d, unknown type = %d\n", level, pItem->type);
        }
        break;
        }
    }
}

void WalkJson(int level, cJSON * json,
    const google::protobuf::Descriptor* pMsgDesc,
    google::protobuf::Message* pMsg)
{
    if (NULL == pMsgDesc || NULL == pMsg)
    {
        printf("NULL == pMsgDesc || NULL == pMsg\n");
        return;
    }

    WalkJsonObject(level, json, pMsgDesc, pMsg);
}
